package secondweek.four;

import org.junit.Test;
import org.nutz.lang.*;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.*;

/**
 * Created by zhourui on 2016/8/11.
 * 随机生成 Salary {name, baseSalary, bonus  }的记录，如“wxxx,10,1”，每行一条记录，总共1000万记录，写入文本文件（UFT-8编码），
 然后读取文件，name的前两个字符相同的，其年薪累加，比如wx，100万，3个人，最后做排序和分组，输出年薪总额最高的10组：
 wx, 200万，10人
 lt, 180万，8人
 ....
 */
public class SaveAndSortSalaryUserChannel {

    @Test
    public void test(){
        File file = new File("D:\\aaa.txt");
//        try {
//            file.createNewFile();
//        } catch (IOException e) {
//            e.printStackTrace();
//        }

        //生成数据，写入文件
        Date timeBegin = Times.now();

//        writeFileUseChannel(file);

        Date afterWriteFile = Times.now();
//        System.out.println("write file:" + (afterWriteFile.getTime()-timeBegin.getTime()) + "ms");

        //读取文件，排序
        Map<String,SalaryTotal> salaries = readFileUseChannel(file);

        SalaryTotal[] salaryTotals = salaries.values().toArray(new SalaryTotal[salaries.size()]);
        Arrays.parallelSort(salaryTotals,new Comparator<SalaryTotal>() {
            public int compare(SalaryTotal o1, SalaryTotal o2) {
                return o1.getTotal() - o2.getTotal();
            }
        });

        Date getTenTop = Times.now();
        System.out.println("read combine and sort:" +
                (getTenTop.getTime()-afterWriteFile.getTime()) + "ms");

        if (salaryTotals.length > 10){
            for (int i = salaryTotals.length-1; i > salaryTotals.length-11; i--){
                System.out.println(salaryTotals[i].getTwoWords()+","
                        +salaryTotals[i].getTotal()+"万,"+salaryTotals[i].getNum()+"人");
            }
        }

        System.out.println("total:" + (getTenTop.getTime()-timeBegin.getTime()) + "ms");
//        Files.deleteFile(file);
    }

    private void writeFileUseChannel(File file){
        FileChannel fileChannel = null;
        try {
            RandomAccessFile randomAccessFile = new RandomAccessFile(file,"rw");
            fileChannel = randomAccessFile.getChannel();
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
            byteBuffer.clear();

            for (int i = 0; i < 10000000; i++){
                Salary salary = new Salary(generateSixChar(),
                        (new Random().nextInt(10)+1),new Random().nextInt(50));
                byteBuffer.put((salary.toString()+"\n").getBytes(Encoding.CHARSET_UTF8));
                if (i % 100  == 0 || i == (10000000-1)){
                    byteBuffer.flip();
                    fileChannel.write(byteBuffer);
                    byteBuffer.clear();
                }
            }
        } catch (IOException var7) {
            var7.printStackTrace();
        }finally {
            if (fileChannel != null){
                try {
                    fileChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private Map<String,SalaryTotal> readFileUseChannel(File file){
        String eachRead = "";
        String[] lines;
        FileChannel fileChannel = null;
        Map<String,SalaryTotal> salaryTotalMap = new HashMap<>();
        try {
            RandomAccessFile randomAccessFile = new RandomAccessFile(file,"rw");
            fileChannel = randomAccessFile.getChannel();
            int allocateLenght = 10240;
            ByteBuffer byteBuffer = ByteBuffer.allocate(allocateLenght);
            int readLength;
            while ((readLength = fileChannel.read(byteBuffer)) != -1){
                byteBuffer.flip();
                eachRead = new String(byteBuffer.array(),0,readLength, Encoding.CHARSET_UTF8);
                if (Strings.isNotBlank(eachRead)){
                    lines = eachRead.substring(0, eachRead.lastIndexOf("\n")).split("\n");
                    for (int i = 0; i < lines.length; i++){
                        if(Strings.isNotBlank(lines[i]) && !"\n".equals(lines[i])){
                            String[] salaryArray = lines[i].split(",");
                            int total = Integer.parseInt(salaryArray[1]) * 12 +
                                    Integer.parseInt(salaryArray[2]);
                            String firstTwo  = salaryArray[0].substring(0,2);
                            SalaryTotal salaryTotal = salaryTotalMap.get(firstTwo);
                            if (salaryTotal != null){
                                salaryTotal.setTotal(salaryTotal.getTotal()+total);
                                salaryTotal.setNum(salaryTotal.getTotal()+1);
                            }else{
                                SalaryTotal salaryTeam = new SalaryTotal(firstTwo,total,1);
                                salaryTotalMap.put(firstTwo,salaryTeam);
                            }
                        }
                    }
                }
                if (fileChannel.position() < fileChannel.size()){
                    fileChannel = fileChannel.position(fileChannel.position()
                            - (eachRead.length() -1 -  eachRead.lastIndexOf("\n")));
                }
                byteBuffer.clear();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ArrayIndexOutOfBoundsException e){
            System.out.println(eachRead);
            e.printStackTrace();
        } catch (StringIndexOutOfBoundsException e){
            System.out.println(eachRead);
            e.printStackTrace();
        }

        finally {
            if (fileChannel != null){
                try {
                    fileChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return salaryTotalMap;
    }

    private static String generateSixChar() {
        String a = "abcdefghijklmnopqrstuvwxyz";
        char[] rands = new char[4];
        for (int i = 0; i < rands.length; i++) {
            int rand = (int) (Math.random() * a.length());
            rands[i] = a.charAt(rand);
        }
        return new String(rands);
    }

}
